package tech.lq0.dreamaticvoyage.block.entity;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Mth;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import tech.lq0.dreamaticvoyage.capability.ModCapabilities;
import tech.lq0.dreamaticvoyage.capability.uce.UCEnergyStorage;

public abstract class AbstractBreadEnergyBlockEntity extends AbstractUCEProviderBlockEntity {

    // 最大UCE容量
    protected final int capacity;
    // 传输速度
    protected final int transferSpeed;

    protected LazyOptional<UCEnergyStorage> energyHandler;

    public AbstractBreadEnergyBlockEntity(BlockEntityType<?> pType, BlockPos pPos, BlockState pBlockState, Builder builder) {
        super(pType, pPos, pBlockState, builder.range, builder.maxConnectCount);

        this.capacity = builder.capacity;
        this.transferSpeed = builder.transferSpeed;
        this.energyHandler = LazyOptional.of(() -> new UCEnergyStorage(builder.capacity));
    }

    /**
     * 自动移除失效链接
     */
    public void refreshConnections(Level pLevel, BlockPos pPos) {
        this.connections.removeIf(offset -> {
            var newPos = new BlockPos(pPos.getX() + offset[0], pPos.getY() + offset[1], pPos.getZ() + offset[2]);
            var blockEntity = pLevel.getBlockEntity(newPos);
            return blockEntity == null || !blockEntity.getCapability(ModCapabilities.UMISU_CURRENT_ENERGY_CAPABILITY).isPresent();
        });
    }

    protected void transferEnergy(Level pLevel, BlockPos pPos) {
        if (this.energyHandler.map(UCEnergyStorage::getEnergyStored).orElse(0) > 0) {
            // 尝试发送能量
            this.connections.forEach(offset -> {
                var newPos = new BlockPos(pPos.getX() + offset[0], pPos.getY() + offset[1], pPos.getZ() + offset[2]);
                var blockEntity = pLevel.getBlockEntity(newPos);
                if (blockEntity == null) return;

                blockEntity.getCapability(ModCapabilities.UMISU_CURRENT_ENERGY_CAPABILITY).ifPresent(targetBlockHandler -> {
                    if (targetBlockHandler.canReceive() && targetBlockHandler.getEnergyStored() < targetBlockHandler.getMaxEnergyStored()) {
                        int energy = targetBlockHandler.receiveEnergy(this.transferSpeed, false);
                        this.energyHandler.ifPresent(handler -> handler.extractEnergy(energy, false));

                        blockEntity.setChanged();
                        this.setChanged();
                    }
                });
            });
            this.setChanged();
        }
    }

    @Override
    boolean canBeCharged(BlockEntity energySource) {
        return true;
    }

    @Override
    public void load(CompoundTag pTag) {
        super.load(pTag);

        if (pTag.contains("UmisuEnergy")) {
            getCapability(ModCapabilities.UMISU_CURRENT_ENERGY_CAPABILITY).ifPresent(handler -> ((UCEnergyStorage) handler).deserializeNBT(pTag.get("UmisuEnergy")));
        }
    }

    @Override
    protected void saveAdditional(CompoundTag pTag) {
        super.saveAdditional(pTag);

        getCapability(ModCapabilities.UMISU_CURRENT_ENERGY_CAPABILITY).ifPresent(handler -> pTag.put("UmisuEnergy", ((UCEnergyStorage) handler).serializeNBT()));
    }

    @Override
    public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
        if (cap == ModCapabilities.UMISU_CURRENT_ENERGY_CAPABILITY) {
            return this.energyHandler.cast();
        }
        return super.getCapability(cap, side);
    }

    @Override
    public CompoundTag getUpdateTag() {
        return this.saveWithFullMetadata();
    }

    @Override
    public void reviveCaps() {
        super.reviveCaps();
        this.energyHandler = LazyOptional.of(() -> new UCEnergyStorage(this.capacity));
    }

    @Override
    public void saveToItem(ItemStack pStack) {
        CompoundTag tag = new CompoundTag();
        getCapability(ModCapabilities.UMISU_CURRENT_ENERGY_CAPABILITY).ifPresent(handler -> {
            tag.put("UmisuEnergy", ((UCEnergyStorage) handler).serializeNBT());
            tag.putInt("MaxUmisuEnergy", handler.getMaxEnergyStored());
        });
        BlockItem.setBlockEntityData(pStack, this.getType(), tag);
    }

    public static class Builder {

        int range = 4;
        int capacity = 100000;
        int maxConnectCount = 6;
        int transferSpeed = 128;

        public Builder range(int range) {
            this.range = Mth.clamp(range, 0, 127);
            return this;
        }

        public Builder capacity(int capacity) {
            this.capacity = Math.max(0, capacity);
            return this;
        }

        public Builder maxConnectCount(int maxConnectCount) {
            this.maxConnectCount = Math.max(0, maxConnectCount);
            return this;
        }

        public Builder transferSpeed(int transferSpeed) {
            this.transferSpeed = Math.max(0, transferSpeed);
            return this;
        }
    }
}
